#include "usart.h"

#include <stdio.h>
#include <string.h>

#include "cfg.h"
#include "cmsis_os.h"

QueueHandle_t rxQueueHandle;
uint8_t uart_data;

static uint8_t rxBuffer[RX_BUFFER_SIZE];
static uint16_t rxIndex = 0;
static uint32_t lastRxTime = 0;

int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}

int fgetc(FILE *f) {
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
}

UART_HandleTypeDef huart4;
UART_HandleTypeDef huart1;

void MX_UART4_Init(void) {
    huart4.Instance = UART4;
    huart4.Init.BaudRate = cfg.rs485_buad;
    huart4.Init.WordLength = UART_WORDLENGTH_8B;
    huart4.Init.StopBits = UART_STOPBITS_1;
    huart4.Init.Parity = UART_PARITY_NONE;
    huart4.Init.Mode = UART_MODE_TX_RX;
    huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart4.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart4) != HAL_OK) {
        printf("uart4 init err\r\n");
        Error_Handler();
    }
}

void MX_USART1_UART_Init(void) {
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }
}

void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (uartHandle->Instance == UART4) {
        __HAL_RCC_UART4_CLK_ENABLE();

        __HAL_RCC_GPIOC_CLK_ENABLE();
        /**UART4 GPIO Configuration
        PC10     ------> UART4_TX
        PC11     ------> UART4_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* UART4 interrupt Init */
        HAL_NVIC_SetPriority(UART4_IRQn, 6, 0);
        HAL_NVIC_EnableIRQ(UART4_IRQn);
    } else if (uartHandle->Instance == USART1) {
        __HAL_RCC_USART1_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART1 interrupt Init */
        HAL_NVIC_SetPriority(USART1_IRQn, 6, 0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) {
    if (uartHandle->Instance == UART4) {
        __HAL_RCC_UART4_CLK_DISABLE();

        /**UART4 GPIO Configuration
        PC10     ------> UART4_TX
        PC11     ------> UART4_RX
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10 | GPIO_PIN_11);

        /* UART4 interrupt Deinit */
        HAL_NVIC_DisableIRQ(UART4_IRQn);
    } else if (uartHandle->Instance == USART1) {
        __HAL_RCC_USART1_CLK_DISABLE();

        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);

        /* USART1 interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART1_IRQn);
    }
}

void reset_uart() {
    printf("reset uart\r\n");
    osDelay(20);
    HAL_UART_AbortReceive_IT(&huart4);
    HAL_UART_DeInit(&huart4);

    osDelay(20);
    MX_UART4_Init();
    osDelay(20);
    if (HAL_UART_Receive_IT(&huart4, &uart_data, 1) != HAL_OK) {
        printf("Failed to restart UART reception\r\n");
    } else {
        printf("UART reception restarted successfully\r\n");
    }
};

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == UART4) {
        lastRxTime = HAL_GetTick();

        if (rxIndex < RX_BUFFER_SIZE) {
            rxBuffer[rxIndex++] = uart_data;
            if (rxIndex >= 11) {
                if (rxBuffer[0] == CMD_HEADER && rxBuffer[1] == 0x55 &&
                    rxBuffer[2] == CMD_HEADER && rxBuffer[3] == 0x55) {
                    uint16_t dataLength = (rxBuffer[7] << 8) | rxBuffer[8];
                    if (rxIndex >= (9 + dataLength + 2)) {
                        osMessagePut(rxQueueHandle, 1, 0);
                    }
                }
            }
        } else {
            rxIndex = 0;
            memset(rxBuffer, 0, RX_BUFFER_SIZE);
        }

        HAL_UART_Receive_IT(&huart4, &uart_data, 1);
    }
}

void usart_send_ack(uint8_t *data, uint16_t len, int index) {
		HAL_UART_Transmit(&huart4, data, len, 1000);
}

void StartUsartTask(void const *argument) {
    printf("usart task start\r\n");
    uint32_t currentTime;
    osEvent event;

    uint8_t localBuffer[RX_BUFFER_SIZE];
    uint16_t localLength;

    //    while (cfg.com_mode != RS485_MODE) {
    //        osDelay(1000);
    //    }

    HAL_UART_Receive_IT(&huart4, &uart_data, 1);
    for (;;) {
        currentTime = HAL_GetTick();
        if ((rxIndex > 0) && ((currentTime - lastRxTime) > CMD_TIMEOUT_MS)) {
            taskENTER_CRITICAL();
            rxIndex = 0;
            memset(rxBuffer, 0, RX_BUFFER_SIZE);
            taskEXIT_CRITICAL();
        }

        event = osMessageGet(rxQueueHandle, 100);

        if (event.status == osEventMessage) {
            // printf("recv usart message\r\n");
            taskENTER_CRITICAL();
            memcpy(localBuffer, rxBuffer, rxIndex);
            localLength = rxIndex;
            rxIndex = 0;
            memset(rxBuffer, 0, RX_BUFFER_SIZE);
            taskEXIT_CRITICAL();

            //            if (cfg.com_mode != RS485_MODE) {
            //                continue;
            //            }
            cmd_process_detail(localBuffer, localLength, usart_send_ack, -1);
        }

        osDelay(1);
    }
}

/* USER CODE END 1 */
